package auctionhausen



import grails.test.mixin.*
import org.junit.*

/**
 * See the API for {@link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
 */
@TestFor(Listing)
class ListingUnitTests {

	//name field constants
	def VALID_NAMES = ['name'];
	static final Integer MAX_NAME_SIZE = 63
	void testNameConstants() {
		VALID_NAMES.each {
			assertTrue it.length() <= MAX_NAME_SIZE
		}	
	}
	
	//date field constants
	def VALID_DATES = [new Date() + 1]
	def INVALID_DATES = [new Date(), new Date() - 1]
	def validateDate = {date ->
		return date > new Date()	
	}
	void testDateConstants() {
		VALID_DATES.each {
			assertTrue validateDate(it)
		}
		
		INVALID_DATES.each {
			assertFalse validateDate(it)
		}
	}
	
	//starting price field constants
	static final Float MIN_STARTING_PRICE = 0.0F
	
	//description field constants
	static final Integer MAX_DESCRIPTION_SIZE = 255
	
	//L-1: Listings have the following required fields: name, end date/time, and
	//	   starting bid price (unit test)
	void testRequiredFieldsMissingCausesValidationErrors() {
		def invalidListing = new Listing(name : null, endDate : null, startingPrice : null);
		invalidListing.validate()
		assertEquals('nullable', invalidListing.errors['name'].code)
		assertEquals('nullable', invalidListing.errors['endDate'].code)
		assertEquals('nullable', invalidListing.errors['startingPrice'].code)
	}

	//L-1: Listings have the following required fields: name, end date/time, and
	//	   starting bid price (unit test)
	void testRequiredFieldsPresentDoesNotCauseValidationErrors() {
		def listing = new Listing(
			name : VALID_NAMES[0], endDate : VALID_DATES[0], 
			startingPrice : MIN_STARTING_PRICE)
		
		listing.validate()
		assertNull listing.errors['name']
		assertNull listing.errors['endDate']
		assertNull listing.errors['startingPrice']
	}

	//L-2: Listings have the following optional fields: description (unit test)
	void testDescriptionFieldIsOptional() {
		[null].each {
			def listing = new Listing(description : it)
			listing.validate()
			assertNull listing.errors['description']
		}
	}

	//L-3: Listings are required to have a seller (Customer) (unit test)
	void testRequiredSellerMissingCausesValidationError() {
		def listing = new Listing(seller : null)
		listing.validate()
		assertEquals('nullable', listing.errors['seller'].code)
	}

	//L-4: Listing descriptions must be less than MAX_DESCRIPTION_SIZE 
	//     characters (unit test)
	void testListingWithTooLongDescriptionCausesValidationErrors() {
		def stringBuilder = new StringBuilder('')
		(1..(MAX_DESCRIPTION_SIZE + 1)).each { stringBuilder.append 'a' }

		def tooLongDescription = stringBuilder.toString()
		assertTrue tooLongDescription.length() > MAX_DESCRIPTION_SIZE

		def listing = new Listing(description : tooLongDescription)
		listing.validate()
		assertEquals('maxSize.exceeded', listing.errors['description'].code)
	}

	//L-4: Listing descriptions must be less than MAX_DESCRIPTION_SIZE 
	//     characters (unit test)
	void testListingWithValidDescriptionLengthDoesNotCauseValidationErrors() {
		def stringBuilder = new StringBuilder('')
		(1..(MAX_DESCRIPTION_SIZE)).each { stringBuilder.append 'a' }

		def validLengthDescription = stringBuilder.toString()
		assertTrue validLengthDescription.length() == MAX_DESCRIPTION_SIZE

		def listing = new Listing(description : validLengthDescription)
		listing.validate()
		assertNull listing.errors['description']
	}

	//L-5: Listing end date/time must be in the future (unit test)
	void testInvalidDatesCausesValidationErrors() {
		INVALID_DATES.each {
			def listing = new Listing (endDate : it)
			listing.validate()
			assertEquals('min.notmet', listing.errors['endDate'].code)
		}
	}

	//L-5: Listing end date/time must be in the future (unit test)
	void testValidDatesDoNotCauseValidationErrors() {
		VALID_DATES.each {
			def listing = new Listing (endDate : it)
			listing.validate()
			assertNull listing.errors['endDate']
		}
	}

	//L-6: Listing name must be less than MAX_NAME_SIZE characters
	void testListingWithTooLongNameCausesValidationErrors() {
		def nameBuilder = new StringBuilder('')
		(1..(MAX_NAME_SIZE + 1)).each { nameBuilder.append('a') }
		
		def name = nameBuilder.toString()
		assertTrue name.length() > MAX_NAME_SIZE
		
		def listing = new Listing(name : name)
		listing.validate()
		assertEquals('maxSize.exceeded', listing.errors['name'].code)
	}

	//L-6: Listing name must be less than MAX_NAME_SIZE characters
	void testListingWithValidNameLengthDoesNotCauseValidationErrors() {
		def nameBuilder = new StringBuilder('')
		(1..MAX_NAME_SIZE).each { nameBuilder.append('a') }
		
		def name = nameBuilder.toString()
		assertTrue MAX_NAME_SIZE >= name.length()
		
		def listing = new Listing(name : name)
		listing.validate()
		assertNull listing.errors['name']
	}

	//L-7: Listing has a nullable field for the winner (Customer) (unit test)
	void testListingWithNullWinnerDoesNotCauseValidationErrors() {
		def listing = new Listing(winner : null)
		listing.validate()
		assertNull listing.errors['winner']
	}
	
	// B-4: A Listing has a list of Bids for that Listing (unit test)
	void testListingHasAListOfBids() {
		def listing = new Listing()
		final Integer BID_COUNT = 4
		(1..BID_COUNT).each {
			listing.addToBids(new Bid())
		}
		
		assertNotNull listing.getBids()
		assertEquals(BID_COUNT, listing.getBids().size())
		assertTrue listing.getBids().getClass().getName().contains('List')
	}
}
